/*
 * @file chip_sct.c
 * @author suyong_yq@126.com
 *
 * @brief LPC8xx SCT driver
 * @note
 * 基于LPCOpen中sct_8xx及sct_pwm_8xx驱动程序改写
 */

#include "chip_sct_8xx.h"

void Chip_SCT_ConfigCounter(LPC_SCT_T *base, const SCT_CounterConfig_T *config)
{
    uint32_t tmp32 = 0U;

    if (config->CounterMode == eSCT_CounterMode_32bitx1)
    {
        tmp32 |= SCT_CONFIG_UNIFY_MASK;
    }
    tmp32 |= SCT_CONFIG_CLKMODE(config->ClockSource)
           | SCT_CONFIG_CKSEL(config->ClockEdge)
           | (config->EnableNoReloadCounterMaskValue << SCT_CONFIG_NORELAOD_L_SHIFT)
           | SCT_CONFIG_INSYNC(config->SyncInputMaskValue)
           | (config->EnableAutoLimitCounterMaskValue << SCT_CONFIG_AUTOLIMIT_L_SHIFT);

    base->CONFIG = tmp32;
}

void Chip_SCT_ControlCounter(LPC_SCT_T *base, uint32_t counterIdMask, SCT_CounterCtrlCmd_T cmd, uint32_t param)
{
    uint32_t cntIdMskValue = 0U;

    if ( 0U != (SCT_COUNTER_ID_Low16bit_MASK & counterIdMask) )
    {
        cntIdMskValue |= 0x1; /* 对L计数器的控制在高16位 */
    }
    if ( 0U != (SCT_COUNTER_ID_High16bit_MASK & counterIdMask) )
    {
        cntIdMskValue |= 0x10000; /* 对H计数器的控制在高16位 */
    }

    switch (cmd)
    {
    case eSCT_CounterCtrlCmd_DOWN   :
    case eSCT_CounterCtrlCmd_STOP   :
    case eSCT_CounterCtrlCmd_HALT   :
    case eSCT_CounterCtrlCmd_CLRCTR :
    case eSCT_CounterCtrlCmd_BIDIR  :
        base->CTRL_U = (base->CTRL_U & ~(cntIdMskValue * cmd)) /* 将cmd对应的bit清零 */
                   | (cntIdMskValue * cmd * param); /* 将param值写入cmd对应的bit位 */
        break;
    case eSCT_CounterCtrlCmd_PRE:
        base->CTRL_U = ( base->CTRL_U & ~(cntIdMskValue * SCT_CTRL_PRE_L_MASK) )
                     | ( (cntIdMskValue * param) << SCT_CTRL_PRE_L_SHIFT );
        break;
    }
}

uint32_t Chip_SCT_GetCurrentCounterValue(LPC_SCT_T *base, uint32_t counterId)
{
    uint32_t ret32;

    switch (counterId)
    {
    case SCT_COUNTER_ID_Low16bit_MASK : /* SCT_COUNTER_ID_Low16bit_MASK & SCT_COUNTER_ID_Unify32bit_MASK */
        ret32 = base->STATE_L;
        break;
    case SCT_COUNTER_ID_High16bit_MASK: /* SCT_COUNTER_ID_High16bit_MASK */
        ret32 = base->STATE_H;
        break;
    default:
        break;
    }

    return ret32;
}

void Chip_SCT_EnableEvent(LPC_SCT_T *base, uint32_t eventMask, bool enable)
{
    if (enable)
    {
        base->EVEN |= eventMask;
    }
    else
    {
        base->EVEN &= ~eventMask;
    }
}

void Chip_SCT_EnableEventInterrupt(LPC_SCT_T *base, uint32_t eventMask, bool enable)
{
    if (enable)
    {
        base->EVEN |= eventMask;
    }
    else
    {
        base->EVEN &= ~eventMask;
    }
}

uint32_t Chip_SCT_GetEventFlag(LPC_SCT_T *base)
{
    return base->EVFLAG;
}

void Chip_SCT_ClearEventFlag(LPC_SCT_T *base, uint32_t eventMask)
{
    base->EVFLAG = eventMask; /* Write 1s to clear. */
}

void Chip_SCT_PreSetEventLimitCounterCmd(LPC_SCT_T *base, uint32_t counterIdMask, uint16_t eventMask, bool enable)
{
    if ( 0U != (SCT_COUNTER_ID_Low16bit_MASK & counterIdMask) )
    {
        if (enable)
        {
            base->LIMIT_L |= eventMask;
        }
        else
        {
            base->LIMIT_L &= ~eventMask;
        }
    }
    if ( 0U != (SCT_COUNTER_ID_High16bit_MASK & counterIdMask) )
    {
        if (enable)
        {
            base->LIMIT_H |= eventMask;
        }
        else
        {
            base->LIMIT_H &= ~eventMask;
        }
    }
}

void Chip_SCT_PreSetEventHaltCounterCmd(LPC_SCT_T *base, uint32_t counterIdMask, uint16_t eventMask, bool enable)
{
    if ( 0U != (SCT_COUNTER_ID_Low16bit_MASK & counterIdMask) )
    {
        if (enable)
        {
            base->HALT_L |= eventMask;
        }
        else
        {
            base->HALT_L &= ~eventMask;
        }
    }
    if ( 0U != (SCT_COUNTER_ID_High16bit_MASK & counterIdMask) )
    {
        if (enable)
        {
            base->HALT_H |= eventMask;
        }
        else
        {
            base->HALT_H &= ~eventMask;
        }
    }
}

void Chip_SCT_PreSetEventStopCounterCmd(LPC_SCT_T *base, uint32_t counterIdMask, uint16_t eventMask, bool enable)
{
    if ( 0U != (SCT_COUNTER_ID_Low16bit_MASK & counterIdMask) )
    {
        if (enable)
        {
            base->STOP_L |= eventMask;
        }
        else
        {
            base->STOP_L &= ~eventMask;
        }
    }
    if ( 0U != (SCT_COUNTER_ID_High16bit_MASK & counterIdMask) )
    {
        if (enable)
        {
            base->STOP_H |= eventMask;
        }
        else
        {
            base->STOP_H &= ~eventMask;
        }
    }
}

void Chip_SCT_PreSetEventStartCounterCmd(LPC_SCT_T *base, uint32_t counterIdMask, uint16_t eventMask, bool enable)
{
    if ( 0U != (SCT_COUNTER_ID_Low16bit_MASK & counterIdMask) )
    {
        if (enable)
        {
            base->START_L |= eventMask;
        }
        else
        {
            base->START_L &= ~eventMask;
        }
    }
    if ( 0U != (SCT_COUNTER_ID_High16bit_MASK & counterIdMask) )
    {
        if (enable)
        {
            base->START_H |= eventMask;
        }
        else
        {
            base->START_H &= ~eventMask;
        }
    }
}

void Chip_SCT_PreSetEventSetOutputCmd(LPC_SCT_T *base, uint32_t outputId, uint16_t eventMask, bool enable)
{
    if (enable)
    {
        base->OUT[outputId].SET |= eventMask;
    }
    else
    {
        base->OUT[outputId].SET &= ~eventMask;
    }
}

void Chip_SCT_PreSetEventClearOutputCmd(LPC_SCT_T *base, uint32_t outputId, uint16_t eventMask, bool enable)
{
    if (enable)
    {
        base->OUT[outputId].CLR |= eventMask;
    }
    else
    {
        base->OUT[outputId].CLR &= ~eventMask;
    }
}

/*
* outputId的有效值为0-5.
*/
void Chip_SCT_SetOutputConflictSolution(LPC_SCT_T *base, uint32_t outputId, SCT_OutputConflictResolution_T resolution)
{
     base->RES = (base->RES & ~(0x3 << (outputId << 1)))
               | (resolution) << (outputId << 1);
}

void Chip_SCT_SetOutputModeInBiDirCounting(LPC_SCT_T *base, uint32_t outputId, SCT_OutputModeInBiDirCounting_T mode)
{
    base->OUTPUTDIRCTRL = (base->RES & ~(0x3 << (outputId << 1)))
               | (mode) << (outputId << 1);
}

/* Match模式或是Capture模式 */
void Chip_SCT_SetEventModes(LPC_SCT_T *base, uint32_t counterIdMask, uint16_t eventMask, SCT_EventCounterMode_T mode)
{
    if ( 0U != (SCT_COUNTER_ID_Low16bit_MASK & counterIdMask) )
    {
        if (eSCT_EventCounterMode_Match == mode)
        {
            base->REGMODE_L &= ~eventMask;
        }
        else
        {
            base->REGMODE_L |= eventMask;
        }
    }
    if ( 0U != (SCT_COUNTER_ID_High16bit_MASK & counterIdMask) )
    {
        if (eSCT_EventCounterMode_Match == mode)
        {
            base->REGMODE_H &= ~eventMask;
        }
        else
        {
            base->REGMODE_H |= eventMask;
        }
    }
}

void Chip_SCT_SetEventMatchValue(LPC_SCT_T *base, uint32_t counterIdMask, uint32_t matchRegIdx, uint32_t value)
{
    if ( 0U != (SCT_COUNTER_ID_Low16bit_MASK & counterIdMask) )
    {
        if (SCT_CONFIG_UNIFY_MASK == (SCT_CONFIG_UNIFY_MASK & base->CONFIG))
        {
            base->MATCH[matchRegIdx].U = value;
        }
        else
        {
            base->MATCH[matchRegIdx].L = (uint16_t)value;
        }
    }
    if ( 0U != (SCT_COUNTER_ID_High16bit_MASK & counterIdMask) )
    {
        base->MATCH[matchRegIdx].H = (uint16_t)value;
    }
}

void Chip_SCT_SetEventMatchReloadValue(LPC_SCT_T *base, uint32_t counterIdMask, uint32_t matchRegIdx, uint32_t value)
{
    if ( 0U != (SCT_COUNTER_ID_Low16bit_MASK & counterIdMask) )
    {
        if (SCT_CONFIG_UNIFY_MASK == (SCT_CONFIG_UNIFY_MASK & base->CONFIG))
        {
            base->MATCHREL[matchRegIdx].U = value;
        }
        else
        {
            base->MATCHREL[matchRegIdx].L = (uint16_t)value;
        }
    }
    if ( 0U != (SCT_COUNTER_ID_High16bit_MASK & counterIdMask) )
    {
        base->MATCHREL[matchRegIdx].H = (uint16_t)value;
    }
}

uint32_t Chip_SCT_GetEventCaptureValue(LPC_SCT_T *base, uint32_t counterId, uint32_t eventIdx)
{
    uint32_t ret32;

    switch (counterId)
    {
    case SCT_COUNTER_ID_Low16bit_MASK : /* SCT_COUNTER_ID_Low16bit_MASK & SCT_COUNTER_ID_Unify32bit_MASK */
        ret32 = base->CAP[counterId].L;
        break;
    case SCT_COUNTER_ID_High16bit_MASK: /* SCT_COUNTER_ID_High16bit_MASK */
        ret32 = base->CAP[counterId].H;
        break;
    default:
        break;
    }

    return ret32;
}

/* 配置事件发生的触发条件
 * 主要操作SCT_EVn_CTRL寄存器
 */
void Chip_SCT_ConfigEventCondition(LPC_SCT_T *base, uint32_t eventIdx, const SCT_EventConditionConfig_T *config)
{
    uint32_t tmp32 = 0U;

    tmp32 = sCT_EV_CTRL_MATCHSEL(config->MatchRegIdx)
          | SCT_EV_CTRL_OUTSEL(config->EventIOMode)
          | SCT_EV_CTRL_IOSEL(config->EventIOIdx)
          | SCT_EV_CTRL_IOCOND(config->EventIOCondition)
          | SCT_EV_CTRL_COMBMODE(config->EventCondition)
          | SCT_EV_CTRL_STATELD(config->EventStateUpdate)
          | SCT_EV_CTRL_STATEV(config->EventUpdateNewValue)
          | SCT_EV_CTRL_DIRECTION(config->EventMatchDirection)
          ;
    if (config->CounterId == SCT_COUNTER_ID_High16bit_MASK)
    {
        tmp32 |= SCT_EV_CTRL_HEVENT_MASK;
    }
    if (config->EnableAdditionalCompareRange)
    {
        tmp32 |= SCT_EV_CTRL_MATCHMEM_MASK;
    }

    base->EV[eventIdx].CTRL = tmp32;
    base->EV[eventIdx].STATE = config->EnableInStatesMaskValue;
}

/* 人为设定当前状态变量值 */
void Chip_SCT_SetCurrentStateVariable(LPC_SCT_T *base, uint32_t counterIdMask, uint16_t curStateValue)
{
    if ( 0U != (SCT_COUNTER_ID_Low16bit_MASK & counterIdMask) )
    {
        //cntIdMskValue |= 0x1; /* 对L计数器的控制在高16位 */
        base->STATE_L = (uint16_t)curStateValue;
    }
    if ( 0U != (SCT_COUNTER_ID_High16bit_MASK & counterIdMask) )
    {
        base->STATE_H = (uint16_t)curStateValue;
    }
}

/* 读取当前状态变量值 */
uint32_t Chip_SCT_GetCurrentStateVariable(LPC_SCT_T *base, uint32_t counterId)
{
    uint32_t ret32;

    switch (counterId)
    {
    case SCT_COUNTER_ID_Low16bit_MASK : /* SCT_COUNTER_ID_Low16bit_MASK & SCT_COUNTER_ID_Unify32bit_MASK */
        ret32 = base->STATE_L;
        break;
    case SCT_COUNTER_ID_High16bit_MASK: /* SCT_COUNTER_ID_High16bit_MASK */
        ret32 = base->STATE_H;
        break;
    default:
        break;
    }
    return ret32;
}

/* EOF. */

